home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / rpg / crossfir.92 / crossfir / crossfire-0.92.5 / common / xutil.c < prev   
C/C++ Source or Header  |  1996-07-24  |  14KB  |  470 lines

  1. /*
  2.  * static char *rcsid_xutil_c =
  3.  *   "$Id: xutil.c,v 1.27 1996/03/04 09:28:05 master Exp $";
  4.  */
  5.  
  6. /*
  7.     CrossFire, A Multiplayer game for X-windows
  8.  
  9.     Copyright (C) 1994 Mark Wedel
  10.     Copyright (C) 1992 Frank Tore Johansen
  11.  
  12.     This program is free software; you can redistribute it and/or modify
  13.     it under the terms of the GNU General Public License as published by
  14.     the Free Software Foundation; either version 2 of the License, or
  15.     (at your option) any later version.
  16.  
  17.     This program is distributed in the hope that it will be useful,
  18.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.     GNU General Public License for more details.
  21.  
  22.     You should have received a copy of the GNU General Public License
  23.     along with this program; if not, write to the Free Software
  24.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  
  26.     The author can be reached via e-mail to master@rahul.net
  27. */
  28.  
  29. #include <global.h>
  30. #include <funcpoint.h>
  31. #include <loader.h>
  32. #ifdef Xpm_Pix
  33. #include <X11/xpm.h>
  34. #endif
  35.  
  36. /* This now merges the color alias and color name table together.
  37.  * The first entry is the color as it is referred to in objects,
  38.  * the second is the actual screen/X11 color to use.  NUM_COLORS is now
  39.  * defined in global.h - if adding colors, increase that value, and everything
  40.  * else should work appropriately.
  41.  */
  42. char *colorname[NUM_COLORS][2] = {
  43. {"black",    "Black"},        /* 0  */
  44. {"white",    "White"},        /* 1  */
  45. {"blue",    "Navy"},        /* 2  */
  46. {"red",        "Red"},            /* 3  */
  47. {"orange",    "Orange"},        /* 4  */
  48. {"light_blue",    "DodgerBlue"},        /* 5  */
  49. {"dark_orange",    "DarkOrange2"},        /* 6  */
  50. {"green",    "SeaGreen"},        /* 7  */
  51. {"light_green",    "DarkSeaGreen"},    /* 8  - Used for window background color */
  52. {"grey",    "Grey50"},        /* 9  */
  53. {"brown",    "Sienna"},        /* 10 */
  54. {"yellow",    "Gold"},        /* 11 */
  55. {"khaki",    "Khaki"}        /* 12 */ 
  56. };
  57.  
  58.  
  59.  
  60. /*
  61.  * Converts between Fontindex and XChar2b types.
  62.  * Used in global.h, for draw_face (in face, FontindextoXChars 
  63.  * is defined to this function name
  64.  */
  65.  
  66. XChar2b fontindex_to_XChar2b(Fontindex s)
  67. {
  68.   XChar2b c;
  69.  
  70.   c.byte1 = s/256;
  71.   c.byte2 = s%256;
  72.  
  73.   return c;
  74. }
  75.  
  76.  
  77. /*
  78.  * ReadPixmaps(): When color pixmaps are used instead of fonts, this function
  79.  * does the actual reading of pixmap-file.  This function is based largely on
  80.  * the ReadBitmaps function.  By Mark Wedel (master@rahul.net)
  81.  */
  82.  
  83. /* New method: Pixmaps are stored as a montage on the disk (in several
  84.  * files).  This way, we only need to call XCreatePixmap... a couple
  85.  * times, and the rest are XCopyArea.  This is much faster, since
  86.  * the XPM library does not seem to be especially efficient about loading
  87.  * large numbers of pixmaps.
  88.  *
  89.  * Return true if we have gone to a private colormap.
  90.  */
  91.  
  92. int ReadPixmaps(Display *gdisp, Pixmap **pixmaps, Pixmap **masks,
  93.     Colormap *cmap) {
  94. #ifdef Xpm_Pix
  95.  
  96.     int    file_num, x, y, num_files, image_num=0,i, image_left, error,depth;
  97.     char    buf[MAX_BUF];
  98.     Pixmap  pixmap, mask;
  99.     Window    root = RootWindow (gdisp,DefaultScreen(gdisp));
  100.     XpmAttributes xpmatribs;
  101.     int        use_private_cmap=0;
  102.  
  103.     /* This function is called before the game gc's are created.  So
  104.      * we create one for our own use here.
  105.      */  
  106.     GC    gc= XCreateGC(gdisp, root, 0, NULL), gc1;
  107.     if (*cmap) {
  108.     xpmatribs.valuemask = XpmColormap;
  109.     xpmatribs.colormap=*cmap;
  110.     }
  111.     else  xpmatribs.valuemask=0;
  112.  
  113.     /* We need a depth 1 gc.  So create a depth 1 pixmap and use that */
  114.     pixmap = XCreatePixmap(gdisp, root, 1, 1, 1);
  115.     gc1= XCreateGC(gdisp, pixmap, 0, NULL);
  116.     XSetGraphicsExposures(gdisp, gc, False);
  117.     XSetGraphicsExposures(gdisp, gc1, False);
  118.     XFreePixmap(gdisp, pixmap);
  119.  
  120.     depth = DefaultDepth(gdisp,DefaultScreen(gdisp));
  121.  
  122.     if (!nrofpixmaps)
  123.       nrofpixmaps = ReadBmapNames ();
  124.     image_left = nrofpixmaps;
  125.  
  126.     /* The processes that create a pixmap already allocates the space for
  127.      * the pixmap data.  Therefor, only space for the pointers to that data
  128.      * needs to be allocated.  The same might apply for the function
  129.      * that creates bitmaps below, but I am not as sure in that case.
  130.      * Mark Wedel (master@rahul.net)
  131.      */
  132.  
  133.     *pixmaps = (Pixmap *) malloc(sizeof(Pixmap *) * nrofpixmaps);
  134.     *masks = (Pixmap *) malloc(sizeof(Pixmap *) * nrofpixmaps);
  135.     for (i=0; i < nrofpixmaps; i++)
  136.       (*pixmaps)[i] = 0;
  137.  
  138.     num_files = nrofpixmaps/ (XPM_MONTAGE_X * XPM_MONTAGE_Y);
  139.     if (nrofpixmaps % (XPM_MONTAGE_X * XPM_MONTAGE_Y)) num_files ++;
  140.  
  141.     LOG(llevDebug,"Building color pixmaps...");
  142.     for (file_num=1; file_num<=num_files; file_num++) {
  143.     sprintf (buf,"%s/%s.pix.%d",LIBDIR, FONTNAME,file_num);
  144. again:    error=XpmReadFileToPixmap(gdisp, root,
  145.           buf,&pixmap,&mask, &xpmatribs);
  146.     if (error!=XpmSuccess) {
  147.         if (error==XpmColorFailed && !use_private_cmap) {
  148.             LOG(llevError,"XPM could not allocate colors - trying to switch to private colormap\n");
  149.             *cmap=XCopyColormapAndFree(gdisp, *cmap);
  150.             xpmatribs.colormap=*cmap;
  151.             use_private_cmap=1;
  152.             goto again;
  153.         }
  154.         LOG(llevError,"Error creating pixmap %s, error %d.\n",buf, error);
  155.     }
  156.     else do {
  157.         x=0;
  158.         y=0;
  159.         for (i=0; i<  (XPM_MONTAGE_X * XPM_MONTAGE_Y); i++) {
  160.         if((*pixmaps)[image_num] != 0)
  161.             LOG(llevError,"Warning: two entries in bmaps: %d\n",i);
  162.         else {
  163.             (*pixmaps)[image_num] = XCreatePixmap(
  164.             gdisp, root, 24, 24, depth);
  165.             (*masks)[image_num]  = XCreatePixmap(
  166.             gdisp, root, 24, 24, 1);
  167.  
  168.             XCopyArea(gdisp, pixmap, (*pixmaps)[image_num],
  169.             gc, x*24, y*24, 24, 24, 0, 0);
  170.             XCopyArea(gdisp, mask, (*masks)[image_num],
  171.             gc1, x*24, y*24, 24, 24, 0, 0);
  172.         }
  173.         x++;
  174.         if (x==XPM_MONTAGE_X) {
  175.             y++;
  176.             x=0;
  177.         }
  178.  
  179.         image_num++;
  180.         image_left--;
  181.         if (!image_left) break;
  182.         if(!(image_num % (CHECK_ACTIVE_MAPS/10))) {
  183.             LOG(llevDebug,".");
  184.                   (*process_active_maps_func)(); /* Process active maps as often as possible */
  185.         }
  186.         }
  187.     } while (image_num<nroffiles && (image_num % (XPM_MONTAGE_X * XPM_MONTAGE_Y)));
  188.     XFreePixmap(gdisp, pixmap);
  189.     XFreePixmap(gdisp, mask);
  190.     }
  191.     XFreeGC(gdisp, gc);
  192.     XFreeGC(gdisp, gc1);
  193.  
  194.     /* Check for any holes.  There should not be.  This is an interim check
  195.      * to use until the xbm_values is removed.  The program that 
  196.      * creates the bitmap/pixmap files just adds the bitmaps, so holes should
  197.      * not be in the image file.
  198.      */
  199.     for (i = 0; i < nrofpixmaps; i++)
  200.     if ((*pixmaps)[i] == 0) {
  201.         LOG(llevDebug, "Warning, pixmap %d is not defined, setting it to blank\n", i);
  202.         pixmaps[i] = pixmaps[blank_face->number];
  203.     }
  204.     return use_private_cmap;
  205. #else
  206.     return 0;    /* Prevents some warning messages */
  207. #endif
  208. }
  209.  
  210. /* This frees all the pixmaps.  This not only makes for better code,
  211.  * some XServers may not free the memory used by the pixmaps unless it is done
  212.  * this way.  For color pixmaps, this will be called twice - the
  213.  * first time, the normal pixmaps will be passed through, the second
  214.  * time, it will be called with the masks as the pixmaps argument.
  215.  */
  216.  
  217. void free_pixmaps(Display *gdisp, Pixmap *pixmaps)
  218. {
  219.     int i;
  220.  
  221.     for (i=0; i < nrofpixmaps; i++) {
  222.     if (pixmaps[i]!=0) {
  223.         XFreePixmap(gdisp, pixmaps[i]);
  224.         pixmaps[i] = 0;
  225.     }
  226.     }
  227. }
  228.  
  229. /*
  230.  * ReadBitmaps(): When bitmaps are used instead of fonts, this function
  231.  * does the actual reading of bitmap-file, and returns the
  232.  * bitmaps array.  It assumes the bitmap file found in the LIBDIR 
  233.  * directory.
  234.  */
  235.   
  236.   
  237. Pixmap *ReadBitmaps(Display *d) {
  238.     char buf[MAX_BUF];
  239.     FILE *fp;
  240.     int i, count = 0,comp;
  241.     Pixmap *pixmaps;
  242.   
  243.     if (!nrofpixmaps)
  244.     nrofpixmaps = ReadBmapNames ();
  245.  
  246.     pixmaps = (Pixmap *) malloc(sizeof(Pixmap) * nrofpixmaps);
  247.     for (i=0; i < nrofpixmaps; i++)
  248.     pixmaps[i] = 0;
  249.   
  250.     sprintf (buf,"%s/%s.cfb",LIBDIR, FONTNAME);
  251.     if ((fp = open_and_uncompress(buf,0,&comp))==NULL) {
  252.     perror("Can't open crossfire.cfb file");
  253.     exit(-1);
  254.       }
  255.   
  256.     LOG(llevDebug,"Building ximages...");
  257.     for (i=0; i<nroffiles; i++) {
  258.     if(pixmaps[i] != 0) {
  259.         LOG(llevError,"Warning: two entries in bmaps: %d\n",i);
  260.         continue;
  261.     }
  262.  
  263.     if (fread (buf, 24 * 3, 1, fp) != 1) {
  264.         LOG(llevError,"Warning: cannot read from file\n");
  265.         break;
  266.     }
  267.  
  268.     pixmaps[i] =  XCreateBitmapFromData
  269.         (d, RootWindow (d, DefaultScreen(d)), buf, 24, 24);
  270.  
  271.     if (!pixmaps[i]) {
  272.         LOG(llevError,"Warning: Cannot create Pixmap %d\n",i);
  273.         pixmaps[i] = 0;
  274.     }
  275.  
  276.     if(++count > CHECK_ACTIVE_MAPS/10) {
  277.         printf (".");
  278.         fflush (stdout);
  279.         count = 0;
  280.         (*process_active_maps_func)();
  281.     }
  282.     }
  283.     close_and_delete(fp, comp);
  284.  
  285.       LOG(llevDebug,"done\n");
  286.  
  287.     /*
  288.      * Now fill out the unused holes with pointers to a blank pixmap
  289.      * to avoid crashes in case trying to draw a nonexistant pixmap.
  290.      */
  291.     for (i = 0; i < nrofpixmaps; i++)
  292.     if (pixmaps[i] == 0)
  293.         pixmaps[i] = pixmaps[blank_face->number];
  294.     return pixmaps;
  295. }
  296.  
  297.  
  298. /*
  299.  * This function adds the path to the fontpath of the given display.
  300.  * It's mostly copied from the X11R5 distribution.
  301.  */
  302.  
  303. void set_font_path(Display *dpy, char *path) {
  304.   char **currentList = NULL; int ncurrent = 0;
  305.   char **directoryList = NULL; int ndirs = 0;
  306.  
  307.   currentList = XGetFontPath (dpy, &ncurrent);
  308.   if(currentList==NULL) {
  309.     LOG(llevError,"Unable to get old font path.\n");
  310.     return;
  311.   }
  312.   {
  313.     register char *cp = path;
  314.     ndirs=1;
  315.     while((cp=strchr(cp, ','))!=NULL)
  316.       ndirs++,cp++;
  317.     directoryList=(char **) malloc(ndirs*sizeof(char *));
  318.     if(!directoryList) {
  319.       LOG(llevError,"Unable to allocate memory for font path directory.\n");
  320.       return;
  321.     }
  322.   }
  323.   {
  324.     int i=0;
  325.     char *cp = path;
  326.     directoryList[i++]=cp;
  327.     while((cp=strchr(cp, ','))!=NULL)
  328.       directoryList[i++]=cp+1,
  329.       *cp++='\0';
  330.     if(i!=ndirs) {
  331.       LOG(llevError,"Internal error, only parsed %d of %d dirs.\n",i,ndirs);
  332.       return;
  333.     }
  334.   }
  335.   {
  336.     int nnew=ndirs+ncurrent;
  337.     char **newList = (char **) malloc (nnew * sizeof(char *));
  338.  
  339.     if(!newList) {
  340.       LOG(llevError,"Couldn't get memory for new fontpath.\n");
  341.       return;
  342.     }
  343. /* #if defined(SYSV) || defined(SVR4) */
  344.     memcpy((void *)newList,(void *)directoryList,
  345.            (unsigned) (ndirs*sizeof (char *)));
  346.     memcpy((void *) (newList + ndirs), (void *) currentList,
  347.            (unsigned) (ncurrent*sizeof (char *)));
  348.     XSetFontPath(dpy,newList, nnew);
  349.     free((char *)newList);
  350.   }
  351.   if (directoryList)
  352.     free((char *) directoryList);
  353.   if (currentList)
  354.     XFreeFontPath (currentList);
  355. }
  356.  
  357. /*
  358.  * Checks if "crossfire" is present somewhere in the fontpath of
  359.  * the given display.
  360.  */
  361.  
  362. int check_font_path(Display *dpy) {
  363.   int count;
  364.   char **list;
  365.  
  366.   list = XListFonts(dpy, font_graphic, 1, &count);
  367.   LOG(llevDebug, "Matching fonts to %s: %d (%s)\n",
  368.       font_graphic,count,count?*list:"");
  369.   XFreeFontNames(list);
  370.   return count;
  371. }
  372.  
  373. /*
  374.  * Uses check_font_path() and set_font_path() to check and, if needed
  375.  * fix the fontpath for the player.
  376.  * Function changed around to make it useful for the client.
  377.  * Passing the player struct to this is not required - xio.c
  378.  * can use the return value to set the use_pixmaps value in the
  379.  * player struct.  name is only passed to give better error
  380.  * messages.
  381.  */
  382.  
  383. int fixfontpath(Display *disp, char *name) {
  384.  
  385.   if (check_font_path(disp))
  386.     return 0;
  387.  
  388.   if(fix_fontpath) {
  389.       LOG(llevError,"Trying to fix fontpath for display %s.\n",name);
  390.       fflush(logfile);
  391.       set_font_path(disp,FontDir);
  392.       if(check_font_path(disp))
  393.         return 0;
  394.   }
  395.   LOG(llevError,"Failed, switching to pixmaps (this might take a while).\n");
  396.   sprintf(errmsg,"Display %s doesn't have the right fontpath.",name);
  397.   return 1;
  398. }
  399.  
  400. /*
  401.  * allocate_colors() tries to get enough colors for the game-window.
  402.  * If it fails, it tries to use a private colormap.
  403.  * If that also fails, it return 1, indicating to the calling
  404.  * function that black and white should be used.
  405.  *
  406.  * Function arguments became a bit more complicated in v0.91.5.
  407.  * The functionality is the same, but instead of passing the player
  408.  * structure, just pass the values that are needed.  This enables
  409.  * the new client to use the function also.
  410.  *
  411.  * Original function by Tyler Van Gorder (tvangod@icst.csuchico.edu),
  412.  * June 1, 1992
  413.  */
  414.  
  415. int allocate_colors(Display *disp, Window w, long screen_num,
  416.     Colormap *colormap, XColor discolor[NUM_COLORS])
  417. {
  418.   int i, tried = 0, depth=0, iscolor;
  419.   Status status;
  420.   Visual *vis;
  421.   XColor exactcolor;
  422.  
  423.   if(no_color) {
  424.     return 0;
  425.   }
  426.   iscolor = 1;
  427.   vis = DefaultVisual(disp,screen_num);
  428.   if (vis->class >= StaticColor) {
  429.     *colormap = DefaultColormap(disp,screen_num);
  430.     depth = DefaultDepth(disp,screen_num);
  431.   }
  432.   else {
  433.     *colormap=(Colormap )NULL;
  434.     LOG(llevError,"Switching to black and white.\n");
  435.     LOG(llevError,"You have a black and white terminal.\n");
  436.     return 0;
  437.   }
  438. try_private:
  439.   if (depth > 3 && iscolor) {
  440.     unsigned long pixels[13];
  441.     for (i=0; i<13; i++){
  442.       status = XLookupColor(disp,*colormap, colorname[i][1],&exactcolor,
  443.                             &discolor[i]);
  444.       if (!status){
  445.         LOG(llevError,"Can't find colour %s.\n", colorname[i]);
  446.         LOG(llevError,"Switching to black and white.\n");
  447.         iscolor = 0;
  448.         break;
  449.       }
  450.       status = XAllocColor(disp,*colormap,&discolor[i]);
  451.       if (!status) {
  452.         if (!tried) {
  453.           LOG(llevError, "Not enough colours. Trying a private colourmap.\n");
  454.           XFreeColors(disp, *colormap, pixels, i-1, 0);
  455.           *colormap = XCreateColormap(disp, w, vis, AllocNone);
  456.           XSetWindowColormap(disp, w, *colormap);
  457.           tried = 1;
  458.           goto try_private;
  459.         } else {
  460.           LOG(llevError, "Failed. Switching to black and white.\n");
  461.           iscolor = 0;
  462.           break;
  463.         }
  464.       }
  465.       pixels[i] = discolor[i].pixel;
  466.     }
  467.   }
  468.   return iscolor;
  469. }
  470.